package com.adee.serializer.kryo;

import com.adee.serializer.util.Animal;
import com.adee.serializer.util.AnimalUtil;
import com.adee.serializer.util.Dog;
import com.adee.serializer.util.Fish;
import com.alibaba.fastjson2.JSON;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;
import org.junit.Test;

import java.io.Serializable;
import java.util.*;

public class TestKryoUtil {

    private static Student student;

    static {
        Map<String,Object> hobbies = new HashMap<>();
        hobbies.put("游泳", "蛙泳自学中...");
        hobbies.put("跑步", "跑一休一");

        List<Teacher> teachers = new ArrayList<>();
        teachers.add(new Teacher(1,"王老师"));
        teachers.add(new Teacher(5, "陈老师"));
        // !!!不能使用如下这种方式创建list，Arrays.asList方法创建的实现类是Arrays.ArrayList，Kryo不支持Arrays.ArrayList，反序列化时会报错
        // Arrays.asList(new Teacher(1,"王老师"),new Teacher(5, "陈老师"));

        student = new Student.StudentBuilder()
                .id(1)
                .name("张三")
//                .teachers(new ArrayList<>(Arrays.asList(new Teacher(1,"王老师"),new Teacher(5, "陈老师"))))
                .teachers(Arrays.asList(new Teacher(1,"王老师"),new Teacher(5, "陈老师")))
                .hobbies(hobbies)
                .build();
    }

    // 测试序列化时不序列化class信息，则反序列化时必须指定实现类Dog.class
    @Test
    public void test01() {
        Animal animal = new Dog();
        System.out.println("序列化之前：");
        System.out.println(JSON.toJSONString(animal));
        byte[] bytes = KryoUtil.writeObjectToByteArray(animal); // 序列化时不序列化class信息

        System.out.println("反序列化之后：");
        Animal a2 = KryoUtil.readObjectFromByteArray(bytes, Dog.class); // 反序列化时必须指定实现类，不然抛异常InstantiationError
        System.out.println(JSON.toJSONString(a2));
    }

    // 测试序列化时序列化class信息，则反序列化时不用指定实现类
    @Test
    public void test02() {
        Animal animal = new Dog();
        System.out.println("序列化之前：");
        System.out.println(JSON.toJSONString(animal));
        byte[] bytes = KryoUtil.writeToByteArray(animal); // 序列化时序列化class信息

        System.out.println("反序列化之后：");
        Animal a2 = KryoUtil.readFromByteArray(bytes); // 反序列化时不用指定实现类
        System.out.println(JSON.toJSONString(a2));
    }

    // 测试反序列化能不能访问接口？答：能
    @Test
    public void test03() {
        Animal animal = new Fish();
        System.out.println("序列化之前：");
        System.out.println(JSON.toJSONString(animal));
        byte[] bytes = KryoUtil.writeToByteArray(animal);

        System.out.println("反序列化之后：");
        Animal a2 = KryoUtil.readFromByteArray(bytes);
        System.out.println(JSON.toJSONString(a2));
    }



    // 测试反序列化能不能访问私有内部类？答：能
    @Test
    public void test04() {
        Animal animal = AnimalUtil.newAnimal();
        System.out.println("序列化之前：");
        System.out.println(JSON.toJSONString(animal));
        byte[] bytes = KryoUtil.writeToByteArray(animal);

        System.out.println("反序列化之后：");
        Animal a2 = KryoUtil.readFromByteArray(bytes);
        a2.run();
        System.out.println(JSON.toJSONString(a2));
    }



    @Test
    public void test1() {

        System.out.println("序列化之前：");
        System.out.println(JSON.toJSONString(student));
        byte[] bytes = KryoUtil.writeToByteArray(student);

        System.out.println("反序列化之后：");
        Student student2 = KryoUtil.readFromByteArray(bytes);
        System.out.println(JSON.toJSONString(student2));
    }

    // 性能测试
    @Test
    public void test2() {
        // 序列化、反序列化 100w次
        long begin = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            byte[] bytes = KryoUtil.writeToByteArray(student);
            Student student2 = KryoUtil.readFromByteArray(bytes);
        }
        long millis = System.currentTimeMillis() -begin;
        System.out.println("Kryo耗时：" + millis); // Kryo耗时：5811  jdk耗时：24238

    }


    @Data
    @Accessors(chain = true)
    @Builder
    public static class Student implements Serializable {
        public static final long serialVersionUID = 2L;

        private long id;
        private String name;

        private List<Teacher> teachers;

        private Map<String,Object> hobbies;
    }

    @Data
    @AllArgsConstructor
    public static class Teacher implements Serializable {
        public static final long serialVersionUID = 1L;

        private long id;
        private String name;
    }


}
